﻿//
// Copyright (c) Ping Castle. All rights reserved.
// https://www.pingcastle.com
//
// Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
//
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Security.Principal;

namespace PingCastle.RPC
{

    [DebuggerDisplay("{Name}")]
    public class SAMR_ENUMERATION_ENTRY
    {
        public long RelativeId;
        public string Name;
    }

    public class samr2 : rpcapi
    {

        private static byte[] MIDL_ProcFormatStringx86 = new byte[] {
                0x00,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x31,0x04,0x00,0x00,0x00,0x5c,0x22,0x00,0x40,0x00,0x44,0x04,0x08,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
                0x0a,0x00,0x00,0x00,0x02,0x00,0x10,0x01,0x04,0x00,0x0a,0x00,0x48,0x00,0x08,0x00,0x08,0x00,0x70,0x00,0x0c,0x00,0x08,0x00,0x00,0x48,0x00,0x00,0x00,0x00,
                0x01,0x00,0x08,0x00,0x30,0xe0,0x00,0x00,0x00,0x00,0x38,0x00,0x40,0x00,0x44,0x02,0x08,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x01,0x00,0x00,0x12,0x00,
                0x70,0x00,0x04,0x00,0x08,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x02,0x00,0x04,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x08,0x01,0x00,0x00,
                0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x03,0x00,0x04,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x08,0x01,0x00,0x00,0x00,0x00,
                0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x04,0x00,0x04,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x08,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
                0x00,0x48,0x00,0x00,0x00,0x00,0x05,0x00,0x10,0x00,0x30,0x40,0x00,0x00,0x00,0x00,0x24,0x00,0x08,0x00,0x47,0x04,0x08,0x07,0x01,0x00,0x01,0x00,0x00,0x00,
                0x08,0x00,0x00,0x00,0x16,0x00,0x0b,0x01,0x04,0x00,0x30,0x00,0x13,0x20,0x08,0x00,0x46,0x00,0x70,0x00,0x0c,0x00,0x08,0x00,0x00,0x48,0x00,0x00,0x00,0x00,
                0x06,0x00,0x18,0x00,0x30,0x40,0x00,0x00,0x00,0x00,0x48,0x00,0x40,0x00,0x45,0x06,0x08,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x16,0x00,
                0x58,0x01,0x04,0x00,0x08,0x00,0x13,0x20,0x08,0x00,0x7c,0x00,0x48,0x00,0x0c,0x00,0x08,0x00,0x50,0x21,0x10,0x00,0x08,0x00,0x70,0x00,0x14,0x00,0x08,0x00,
                0x00,0x48,0x00,0x00,0x00,0x00,0x07,0x00,0x14,0x00,0x30,0x40,0x00,0x00,0x00,0x00,0x2c,0x00,0x40,0x00,0x46,0x05,0x08,0x05,0x00,0x00,0x01,0x00,0x00,0x00,
                0x08,0x00,0x00,0x00,0x16,0x00,0x48,0x00,0x04,0x00,0x08,0x00,0x0b,0x01,0x08,0x00,0x6a,0x00,0x10,0x01,0x0c,0x00,0xee,0x00,0x70,0x00,0x10,0x00,0x08,0x00,
                0x00,0x48,0x00,0x00,0x00,0x00,0x08,0x00,0x04,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x08,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,
                0x00,0x00,0x00,0x00,0x09,0x00,0x04,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x08,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00,
                0x00,0x00,0x0a,0x00,0x04,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x08,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,
                0x0b,0x00,0x04,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x08,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x0c,0x00,
                0x04,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x08,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x0d,0x00,0x1c,0x00,
                0x30,0x40,0x00,0x00,0x00,0x00,0x50,0x00,0x40,0x00,0x45,0x07,0x08,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x16,0x00,0x58,0x01,0x04,0x00,
                0x08,0x00,0x48,0x00,0x08,0x00,0x08,0x00,0x13,0x20,0x0c,0x00,0x7c,0x00,0x48,0x00,0x10,0x00,0x08,0x00,0x50,0x21,0x14,0x00,0x08,0x00,0x70,0x00,0x18,0x00,
                0x08,0x00,0x00
            };

        private static byte[] MIDL_ProcFormatStringx64 = new byte[] {
                0x00,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x31,0x08,0x00,0x00,0x00,0x5c,0x22,0x00,0x40,0x00,0x44,0x04,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
                0x00,0x00,0x0a,0x00,0x00,0x00,0x02,0x00,0x10,0x01,0x08,0x00,0x0a,0x00,0x48,0x00,0x10,0x00,0x08,0x00,0x70,0x00,0x18,0x00,0x08,0x00,0x00,0x48,0x00,0x00,
                0x00,0x00,0x01,0x00,0x10,0x00,0x30,0xe0,0x00,0x00,0x00,0x00,0x38,0x00,0x40,0x00,0x44,0x02,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x01,
                0x00,0x00,0x12,0x00,0x70,0x00,0x08,0x00,0x08,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x02,0x00,0x08,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,
                0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x03,0x00,0x08,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,
                0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,
                0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x05,0x00,0x20,0x00,0x30,0x40,0x00,0x00,0x00,0x00,0x24,0x00,0x08,0x00,
                0x47,0x04,0x0a,0x07,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x16,0x00,0x0b,0x01,0x08,0x00,0x30,0x00,0x13,0x20,0x10,0x00,0x42,0x00,
                0x70,0x00,0x18,0x00,0x08,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x06,0x00,0x30,0x00,0x30,0x40,0x00,0x00,0x00,0x00,0x48,0x00,0x40,0x00,0x45,0x06,0x0a,0x03,
                0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x16,0x00,0x58,0x01,0x08,0x00,0x08,0x00,0x13,0x20,0x10,0x00,0x78,0x00,0x48,0x00,0x18,0x00,
                0x08,0x00,0x50,0x21,0x20,0x00,0x08,0x00,0x70,0x00,0x28,0x00,0x08,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x07,0x00,0x28,0x00,0x30,0x40,0x00,0x00,0x00,0x00,
                0x2c,0x00,0x40,0x00,0x46,0x05,0x0a,0x05,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x16,0x00,0x48,0x00,0x08,0x00,0x08,0x00,0x0b,0x01,
                0x10,0x00,0x66,0x00,0x10,0x01,0x18,0x00,0xc2,0x00,0x70,0x00,0x20,0x00,0x08,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x32,0x00,0x00,0x00,
                0x00,0x00,0x00,0x00,0x40,0x00,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x09,0x00,0x08,0x00,0x32,0x00,0x00,0x00,
                0x00,0x00,0x00,0x00,0x40,0x00,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x0a,0x00,0x08,0x00,0x32,0x00,0x00,0x00,
                0x00,0x00,0x00,0x00,0x40,0x00,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x0b,0x00,0x08,0x00,0x32,0x00,0x00,0x00,
                0x00,0x00,0x00,0x00,0x40,0x00,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x0c,0x00,0x08,0x00,0x32,0x00,0x00,0x00,
                0x00,0x00,0x00,0x00,0x40,0x00,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x0d,0x00,0x38,0x00,0x30,0x40,0x00,0x00,
                0x00,0x00,0x50,0x00,0x40,0x00,0x45,0x07,0x0a,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x16,0x00,0x58,0x01,0x08,0x00,0x08,0x00,
                0x48,0x00,0x10,0x00,0x08,0x00,0x13,0x20,0x18,0x00,0x78,0x00,0x48,0x00,0x20,0x00,0x08,0x00,0x50,0x21,0x28,0x00,0x08,0x00,0x70,0x00,0x30,0x00,0x08,0x00,
                0x00
        };

        private static byte[] MIDL_TypeFormatStringx86 = new byte[] {
                0x00,0x00,0x12,0x08,0x05,0x5c,0x11,0x04,0x02,0x00,0x30,0xa0,0x00,0x00,0x11,0x04,0x02,0x00,0x30,0xe1,0x00,0x00,0x30,0x41,0x00,0x00,0x11,0x00,0x14,0x00,
                0x1c,0x01,0x02,0x00,0x17,0x55,0x02,0x00,0x01,0x00,0x17,0x55,0x00,0x00,0x01,0x00,0x05,0x5b,0x16,0x03,0x08,0x00,0x4b,0x5c,0x46,0x5c,0x04,0x00,0x04,0x00,
                0x12,0x00,0xe0,0xff,0x5b,0x06,0x06,0x08,0x5c,0x5b,0x11,0x14,0x02,0x00,0x12,0x00,0x1e,0x00,0x1d,0x00,0x06,0x00,0x01,0x5b,0x15,0x00,0x06,0x00,0x4c,0x00,
                0xf4,0xff,0x5c,0x5b,0x1b,0x03,0x04,0x00,0x04,0x00,0xf9,0xff,0x01,0x00,0x08,0x5b,0x17,0x03,0x08,0x00,0xf0,0xff,0x02,0x02,0x4c,0x00,0xe0,0xff,0x5c,0x5b,
                0x11,0x08,0x08,0x5c,0x11,0x14,0x02,0x00,0x12,0x00,0x4c,0x00,0x1c,0x01,0x02,0x00,0x17,0x55,0x06,0x00,0x01,0x00,0x17,0x55,0x04,0x00,0x01,0x00,0x05,0x5b,
                0x16,0x03,0x0c,0x00,0x4b,0x5c,0x46,0x5c,0x08,0x00,0x08,0x00,0x12,0x00,0xe0,0xff,0x5b,0x08,0x06,0x06,0x08,0x5b,0x1b,0x03,0x0c,0x00,0x19,0x00,0x00,0x00,
                0x01,0x00,0x4b,0x5c,0x48,0x49,0x0c,0x00,0x00,0x00,0x01,0x00,0x08,0x00,0x08,0x00,0x12,0x00,0xbe,0xff,0x5b,0x4c,0x00,0xcb,0xff,0x5b,0x16,0x03,0x08,0x00,
                0x4b,0x5c,0x46,0x5c,0x04,0x00,0x04,0x00,0x12,0x00,0xd0,0xff,0x5b,0x08,0x08,0x5b,0x11,0x0c,0x08,0x5c,0x11,0x00,0x82,0xff,0x11,0x04,0x02,0x00,0x30,0xa0,
                0x00,0x01,0x00
        };

        private static byte[] MIDL_TypeFormatStringx64 = new byte[] {
                0x00,0x00,0x12,0x08,0x05,0x5c,0x11,0x04,0x02,0x00,0x30,0xa0,0x00,0x00,0x11,0x04,0x02,0x00,0x30,0xe1,0x00,0x00,0x30,0x41,0x00,0x00,0x11,0x00,0x14,0x00,
                0x1c,0x01,0x02,0x00,0x17,0x55,0x02,0x00,0x01,0x00,0x17,0x55,0x00,0x00,0x01,0x00,0x05,0x5b,0x1a,0x03,0x10,0x00,0x00,0x00,0x08,0x00,0x06,0x06,0x40,0x36,
                0x5c,0x5b,0x12,0x00,0xde,0xff,0x11,0x14,0x02,0x00,0x12,0x00,0x1e,0x00,0x1d,0x00,0x06,0x00,0x01,0x5b,0x15,0x00,0x06,0x00,0x4c,0x00,0xf4,0xff,0x5c,0x5b,
                0x1b,0x03,0x04,0x00,0x04,0x00,0xf9,0xff,0x01,0x00,0x08,0x5b,0x17,0x03,0x08,0x00,0xf0,0xff,0x02,0x02,0x4c,0x00,0xe0,0xff,0x5c,0x5b,0x11,0x08,0x08,0x5c,
                0x11,0x14,0x02,0x00,0x12,0x00,0x28,0x00,0x1a,0x03,0x18,0x00,0x00,0x00,0x00,0x00,0x08,0x40,0x4c,0x00,0xa4,0xff,0x5c,0x5b,0x21,0x03,0x00,0x00,0x19,0x00,
                0x00,0x00,0x01,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x4c,0x00,0xde,0xff,0x5c,0x5b,0x1a,0x03,0x10,0x00,0x00,0x00,0x06,0x00,0x08,0x40,0x36,0x5b,0x12,0x00,
                0xdc,0xff,0x11,0x0c,0x08,0x5c,0x11,0x00,0xaa,0xff,0x11,0x04,0x02,0x00,0x30,0xa0,0x00,0x01,0x00
        };

        [StructLayout(LayoutKind.Sequential)]
        private struct SAMPR_ENUMERATION_BUFFER
        {
            public UInt32 EntriesRead;
            public IntPtr Buffer;
        };

        [StructLayout(LayoutKind.Sequential)]
        private struct SAMPR_RID_ENUMERATION
        {
            public IntPtr RelativeId;
            public UInt16 Length;
            public UInt16 MaximumLength;
            public IntPtr buffer;
        };

        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public samr2()
        {
            Guid interfaceId = new Guid(magic(5) + "778-" + magic(4) + "-ABCD-EF00-0123456789AC");
            if (IntPtr.Size == 8)
            {
                InitializeStub(interfaceId, MIDL_ProcFormatStringx64, MIDL_TypeFormatStringx64, "\\pipe\\samr");
            }
            else
            {
                InitializeStub(interfaceId, MIDL_ProcFormatStringx86, MIDL_TypeFormatStringx86, "\\pipe\\samr");
            }
            UseNullSession = true;
        }

        [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        ~samr2()
        {
            freeStub();
        }

        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public Int32 SamrConnect(string server, out IntPtr ServerHandle, UInt32 DesiredAccess)
        {
            IntPtr intptrServer = Marshal.StringToHGlobalUni(server);

            ServerHandle = IntPtr.Zero;
            IntPtr result = IntPtr.Zero;
            try
            {
                ServerHandle = IntPtr.Zero;
                if (IntPtr.Size == 8)
                {
                    result = NativeMethods.NdrClientCall2x64(GetStubHandle(), GetProcStringHandle(0), intptrServer, out ServerHandle, DesiredAccess);
                }
                else
                {
                    IntPtr tempValue = new IntPtr();
                    GCHandle handle = GCHandle.Alloc(tempValue, GCHandleType.Pinned);
                    IntPtr tempValuePointer = handle.AddrOfPinnedObject();
                    try
                    {
                        result = CallNdrClientCall2x86(0, intptrServer, tempValuePointer, new IntPtr((int)DesiredAccess));
                        // each pinvoke work on a copy of the arguments (without an out specifier)
                        // get back the data
                        ServerHandle = Marshal.ReadIntPtr(tempValuePointer);
                    }
                    finally
                    {
                        handle.Free();
                    }
                }
            }
            catch (SEHException)
            {
                Trace.WriteLine("SamrConnect failed 0x" + Marshal.GetExceptionCode().ToString("x"));
                return Marshal.GetExceptionCode();
            }
            finally
            {
                if (intptrServer != IntPtr.Zero)
                    Marshal.FreeHGlobal(intptrServer);
            }
            return (int)result.ToInt64();
        }

        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public Int32 SamrCloseHandle(ref IntPtr ServerHandle)
        {
            IntPtr result = IntPtr.Zero;
            try
            {
                if (IntPtr.Size == 8)
                {
                    result = NativeMethods.NdrClientCall2x64(GetStubHandle(), GetProcStringHandle(56), ref ServerHandle);
                }
                else
                {
                    IntPtr tempValue = ServerHandle;
                    GCHandle handle = GCHandle.Alloc(tempValue, GCHandleType.Pinned);
                    IntPtr tempValuePointer = handle.AddrOfPinnedObject();
                    try
                    {
                        result = CallNdrClientCall2x86(54, tempValuePointer);
                        // each pinvoke work on a copy of the arguments (without an out specifier)
                        // get back the data
                        ServerHandle = Marshal.ReadIntPtr(tempValuePointer);
                    }
                    finally
                    {
                        handle.Free();
                    }
                }
            }
            catch (SEHException)
            {
                Trace.WriteLine("SamrCloseHandle failed 0x" + Marshal.GetExceptionCode().ToString("x"));
                return Marshal.GetExceptionCode();
            }
            return (int)result.ToInt64();
        }

        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public Int32 SamrEnumerateDomainsInSamServer(IntPtr ServerHandle, ref IntPtr EnumerationContext,
            out SAMR_ENUMERATION_ENTRY[] Buffer, UInt32 PreferedMaximumLength, out UInt32 CountReturned)
        {
            IntPtr result = IntPtr.Zero;
            CountReturned = 0;
            try
            {
                IntPtr IntptrBuffer = IntPtr.Zero;
                if (IntPtr.Size == 8)
                {
                    result = NativeMethods.NdrClientCall2x64(GetStubHandle(), GetProcStringHandle(246), ServerHandle, ref EnumerationContext, out IntptrBuffer, PreferedMaximumLength, out CountReturned);
                }
                else
                {
                    IntPtr tempValue1 = EnumerationContext;
                    GCHandle handle1 = GCHandle.Alloc(tempValue1, GCHandleType.Pinned);
                    IntPtr tempValuePointer1 = handle1.AddrOfPinnedObject();
                    IntPtr tempValue2 = IntPtr.Zero;
                    GCHandle handle2 = GCHandle.Alloc(tempValue2, GCHandleType.Pinned);
                    IntPtr tempValuePointer2 = handle2.AddrOfPinnedObject();
                    IntPtr tempValue3 = IntPtr.Zero;
                    GCHandle handle3 = GCHandle.Alloc(tempValue3, GCHandleType.Pinned);
                    IntPtr tempValuePointer3 = handle3.AddrOfPinnedObject();
                    try
                    {
                        result = CallNdrClientCall2x86(234, ServerHandle, tempValuePointer1, tempValuePointer2, new IntPtr(PreferedMaximumLength), tempValuePointer3);
                        // each pinvoke work on a copy of the arguments (without an out specifier)
                        // get back the data
                        EnumerationContext = Marshal.ReadIntPtr(tempValuePointer1);
                        IntptrBuffer = Marshal.ReadIntPtr(tempValuePointer2);
                        CountReturned = (UInt32)Marshal.ReadInt32(tempValuePointer3);
                    }
                    finally
                    {
                        handle1.Free();
                        handle2.Free();
                        handle3.Free();
                    }
                }
                Buffer = Unmarshal_SAMR_ENUMRATION(IntptrBuffer);
            }
            catch (SEHException)
            {
                Buffer = null;
                Trace.WriteLine("SamrEnumerateDomainsInSamServer failed 0x" + Marshal.GetExceptionCode().ToString("x"));
                return Marshal.GetExceptionCode();
            }
            return (int)result.ToInt64();
        }

        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        private SAMR_ENUMERATION_ENTRY[] Unmarshal_SAMR_ENUMRATION(IntPtr IntptrBuffer)
        {
            if (IntptrBuffer == IntPtr.Zero)
                return null;
            SAMPR_ENUMERATION_BUFFER Buffer = (SAMPR_ENUMERATION_BUFFER)Marshal.PtrToStructure(IntptrBuffer, typeof(SAMPR_ENUMERATION_BUFFER));

            SAMR_ENUMERATION_ENTRY[] output = new SAMR_ENUMERATION_ENTRY[Buffer.EntriesRead];
            int size = Marshal.SizeOf(typeof(SAMPR_RID_ENUMERATION));
            for (int i = 0; i < (int)Buffer.EntriesRead; i++)
            {
                output[i] = new SAMR_ENUMERATION_ENTRY();
                SAMPR_RID_ENUMERATION ridenumaration = (SAMPR_RID_ENUMERATION)Marshal.PtrToStructure(new IntPtr(Buffer.Buffer.ToInt64() + size * i), typeof(SAMPR_RID_ENUMERATION));
                output[i].RelativeId = ridenumaration.RelativeId.ToInt64();
                output[i].Name = Marshal.PtrToStringUni(ridenumaration.buffer, ridenumaration.Length / 2);
                if (ridenumaration.buffer != IntPtr.Zero && ridenumaration.MaximumLength > 0)
                    FreeMemory(ridenumaration.buffer);
            }
            if (Buffer.Buffer != IntPtr.Zero)
                FreeMemory(Buffer.Buffer);
            FreeMemory(IntptrBuffer);
            return output;
        }

        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public Int32 SamrLookupDomainInSamServer(IntPtr ServerHandle, string Name, out SecurityIdentifier DomainId)
        {
            IntPtr result = IntPtr.Zero;
            DomainId = null;
            IntPtr sid = IntPtr.Zero;
            using (var NameString = new PingCastle.NativeMethods.UNICODE_STRING())
            {
                try
                {
                    NameString.Initialize(Name);
                    if (IntPtr.Size == 8)
                    {
                        result = NativeMethods.NdrClientCall2x64(GetStubHandle(), GetProcStringHandle(190), ServerHandle, NameString, out sid);
                    }
                    else
                    {
                        GCHandle handle1 = GCHandle.Alloc(NameString, GCHandleType.Pinned);
                        IntPtr tempValuePointer1 = handle1.AddrOfPinnedObject();
                        IntPtr tempValue2 = sid;
                        GCHandle handle2 = GCHandle.Alloc(tempValue2, GCHandleType.Pinned);
                        IntPtr tempValuePointer2 = handle2.AddrOfPinnedObject();
                        try
                        {
                            result = CallNdrClientCall2x86(180, ServerHandle, tempValuePointer1, tempValuePointer2);
                            // each pinvoke work on a copy of the arguments (without an out specifier)
                            // get back the data
                            sid = Marshal.ReadIntPtr(tempValuePointer2);
                        }
                        finally
                        {
                            handle1.Free();
                            handle2.Free();
                        }
                    }
                    DomainId = new SecurityIdentifier(sid);
                    FreeMemory(sid);
                }
                catch (SEHException)
                {
                    Trace.WriteLine("SamrLookupDomainInSamServer failed 0x" + Marshal.GetExceptionCode().ToString("x"));
                    return Marshal.GetExceptionCode();
                }
            }
            return (int)result.ToInt64();
        }

        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public Int32 SamrOpenDomain(IntPtr ServerHandle, Int32 DesiredAccess, SecurityIdentifier DomainId, out IntPtr DomainHandle)
        {
            IntPtr result = IntPtr.Zero;
            DomainHandle = IntPtr.Zero;
            try
            {
                byte[] sid = new byte[DomainId.BinaryLength];
                DomainId.GetBinaryForm(sid, 0);
                if (IntPtr.Size == 8)
                {
                    result = NativeMethods.NdrClientCall2x64(GetStubHandle(), GetProcStringHandle(314), ServerHandle, DesiredAccess, sid, out DomainHandle);
                }
                else
                {
                    GCHandle handle1 = GCHandle.Alloc(sid, GCHandleType.Pinned);
                    IntPtr tempValuePointer1 = handle1.AddrOfPinnedObject();
                    IntPtr tempValue2 = IntPtr.Zero;
                    GCHandle handle2 = GCHandle.Alloc(tempValue2, GCHandleType.Pinned);
                    IntPtr tempValuePointer2 = handle2.AddrOfPinnedObject();
                    try
                    {
                        result = CallNdrClientCall2x86(300, ServerHandle, new IntPtr(DesiredAccess), tempValuePointer1, tempValuePointer2);
                        // each pinvoke work on a copy of the arguments (without an out specifier)
                        // get back the data
                        DomainHandle = Marshal.ReadIntPtr(tempValuePointer2);
                    }
                    finally
                    {
                        handle1.Free();
                        handle2.Free();
                    }
                }
            }
            catch (SEHException)
            {
                Trace.WriteLine("SamrOpenDomain failed 0x" + Marshal.GetExceptionCode().ToString("x"));
                return Marshal.GetExceptionCode();
            }
            return (int)result.ToInt64();
        }

        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public Int32 SamrEnumerateUsersInDomain(IntPtr DomainHandle, ref IntPtr EnumerationContext, Int32 UserAccountControl,
            out SAMR_ENUMERATION_ENTRY[] Buffer, Int32 PreferedMaximumLength, out UInt32 CountReturned)
        {
            IntPtr result = IntPtr.Zero;
            CountReturned = 0;
            try
            {
                IntPtr IntptrBuffer = IntPtr.Zero;
                if (IntPtr.Size == 8)
                {
                    result = NativeMethods.NdrClientCall2x64(GetStubHandle(), GetProcStringHandle(526), DomainHandle, ref EnumerationContext, UserAccountControl, out IntptrBuffer, PreferedMaximumLength, ref CountReturned);
                }
                else
                {
                    IntPtr tempValue1 = EnumerationContext;
                    GCHandle handle1 = GCHandle.Alloc(tempValue1, GCHandleType.Pinned);
                    IntPtr tempValuePointer1 = handle1.AddrOfPinnedObject();
                    IntPtr tempValue2 = IntPtr.Zero;
                    GCHandle handle2 = GCHandle.Alloc(tempValue2, GCHandleType.Pinned);
                    IntPtr tempValuePointer2 = handle2.AddrOfPinnedObject();
                    IntPtr tempValue3 = IntPtr.Zero;
                    GCHandle handle3 = GCHandle.Alloc(tempValue3, GCHandleType.Pinned);
                    IntPtr tempValuePointer3 = handle3.AddrOfPinnedObject();
                    try
                    {
                        result = CallNdrClientCall2x86(500, DomainHandle, tempValuePointer1, new IntPtr(UserAccountControl), tempValuePointer2, new IntPtr(PreferedMaximumLength), tempValuePointer3);
                        // each pinvoke work on a copy of the arguments (without an out specifier)
                        // get back the data
                        EnumerationContext = Marshal.ReadIntPtr(tempValuePointer1);
                        IntptrBuffer = Marshal.ReadIntPtr(tempValuePointer2);
                        CountReturned = (UInt32)Marshal.ReadInt32(tempValuePointer3);
                    }
                    finally
                    {
                        handle1.Free();
                        handle2.Free();
                        handle3.Free();
                    }
                }
                Buffer = Unmarshal_SAMR_ENUMRATION(IntptrBuffer);
            }
            catch (SEHException)
            {
                Buffer = null;
                Trace.WriteLine("SamrEnumerateUsersInDomain failed 0x" + Marshal.GetExceptionCode().ToString("x"));
                return Marshal.GetExceptionCode();
            }
            return (int)result.ToInt64();
        }
    }
}
